package com.spark.lola.logistics.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.spark.lola.feign.LogisticsFeignService;
import com.spark.lola.logistics.constant.LogisticsConstant;
import com.spark.lola.logistics.entity.CarSubscribe;
import com.spark.lola.logistics.entity.LocationInfo;
import com.spark.lola.logistics.mapper.*;
import com.spark.lola.logistics.vo.StatisticsExpensesInfoVo;
import com.spark.lola.logistics.vo.StatisticsOrderInfoVo;
import com.spark.lola.statistics.entity.StatisticsCar;
import com.spark.lola.statistics.entity.StatisticsDriver;
import com.spark.lola.statistics.entity.StatisticsLogistics;
import com.spark.lola.support.common.constant.CommonConstant;
import com.spark.lola.support.common.entity.ShiroUser;
import com.spark.lola.support.mybatis.entity.PageParam;
import com.spark.lola.support.mybatis.entity.QueryParam;
import com.spark.lola.support.wms.cache.CollectionCache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @Author: DengYeJun
 * @Date: 2020/4/28 18:55
 */
public class LogisticsFeignServiceImpl implements LogisticsFeignService {

    private static final Logger logger = LoggerFactory.getLogger(LogisticsFeignServiceImpl.class);

    private final LocationInfoMapper locationInfoMapper;

    private final CarSubscribeMapper carSubscribeMapper;

    private LogisticsOrderInfoMapper logisticsOrderInfoMapper;

    private ExpensesInfoMapper expensesInfoMapper;

    private DriverInfoMapper driverInfoMapper;

    private CarInfoMapper carInfoMapper;

    public LogisticsFeignServiceImpl(LocationInfoMapper locationInfoMapper,
                                     CarSubscribeMapper carSubscribeMapper,
                                     LogisticsOrderInfoMapper logisticsOrderInfoMapper,
                                     ExpensesInfoMapper expensesInfoMapper,
                                     DriverInfoMapper driverInfoMapper, CarInfoMapper carInfoMapper) {
        this.locationInfoMapper = locationInfoMapper;
        this.carSubscribeMapper = carSubscribeMapper;
        this.logisticsOrderInfoMapper = logisticsOrderInfoMapper;
        this.expensesInfoMapper = expensesInfoMapper;
        this.driverInfoMapper = driverInfoMapper;
        this.carInfoMapper = carInfoMapper;
    }

    @Override
    public LocationInfo findById(Long id) {
        LocationInfo model = locationInfoMapper.selectById(id);
        ShiroUser user = CollectionCache.employees.get(model.getEmpId());
        model.setMobile(user.getPhone());
        model.setLinkman(user.getRealName());
        return model;
    }

    @Override
    public IPage<CarSubscribe> findPage(QueryParam<CarSubscribe> queryParam) {
        PageParam<CarSubscribe> pageParam = queryParam.toPageParam();
        return carSubscribeMapper.findPage(pageParam.getPage(), pageParam.getEntityWrapper());
    }

    /**
     * @description: 预订
     * @param: carSubscribeId 回头车预订记录id
     * @param: subscribeId 预订人id
     * @param: subscribeName 预订人姓名
     * @return: void
     * @author: wzp
     * @date: 2020/5/12
     */
    @Override
    public void subscriber(long carSubscribeId, long subscribeId, String subscribeName) throws Exception {
        CarSubscribe carSubscribe = carSubscribeMapper.selectById(carSubscribeId);
        logger.info("====【{}】预订回头车【{}】===START===", subscribeName, carSubscribe.getCarNo());
        if (!CommonConstant.W.equals(carSubscribe.getUsed())) {
            logger.info("====回头车预订（状态错误）失败===END===");
            throw new Exception("状态错误");
        }
        CarSubscribe info = new CarSubscribe();
        info.setId(carSubscribe.getId());
        info.setUsed(CommonConstant.Y);
        info.setSubscribeId(subscribeId);
        info.setSubscribeName(subscribeName);
        info.setSubscribeTime(new Date());
        info.setVersion(carSubscribe.getVersion());
        if (carSubscribeMapper.updateById(info) == 0) {
            logger.info("====回头车预订（更新失败）失败===END===");
            throw new Exception("更新失败");
        }
        logger.info("====回头车预订成功===END===");
    }

    /**
     * @description: 取消预订
     * @param: carSubscribeId 回头车预订记录id
     * @param: subscribeId 取消预订人id
     * @return: void
     * @author: wzp
     * @date: 2020/5/12
     */
    @Override
    public void cancel(long carSubscribeId, long subscribeId) throws Exception {
        CarSubscribe carSubscribe = carSubscribeMapper.selectById(carSubscribeId);
        logger.info("====【{}】取消预订回头车【{}】===START===", carSubscribe.getSubscribeName(), carSubscribe.getCarNo());
        if (carSubscribe.getSubscribeId() != subscribeId) {
            logger.info("====取消回头车预订（非法操作）失败===END===");
            throw new Exception("非法操作");
        }
        if (!CommonConstant.Y.equals(carSubscribe.getUsed())) {
            logger.info("====取消回头车预订（状态错误）失败===END===");
            throw new Exception("状态错误");
        }
        if (carSubscribeMapper.cancelUpdate(CommonConstant.W, carSubscribe.getId(), carSubscribe.getVersion() + 1, carSubscribe.getVersion()) == 0) {
            logger.info("====回头车预订（更新失败）失败===END===");
            throw new Exception("更新失败");
        }
        logger.info("====回头车预订成功===END===");
    }

    @Override
    public List<LocationInfo> getCompany() {
        QueryWrapper<LocationInfo> query = new QueryWrapper<>();
        query.eq("location_type", LogisticsConstant.LocationType.PAPER);
        query.eq("used", CommonConstant.Y);
        List<LocationInfo> lst = locationInfoMapper.selectList(query);
        lst.forEach(o -> {
            ShiroUser user = CollectionCache.employees.get(o.getEmpId());
            o.setMobile(user.getPhone());
            o.setLinkman(user.getRealName());
        });
        return lst;
    }

    @Override
    public Integer getCompanySize() {
        QueryWrapper<LocationInfo> query = new QueryWrapper<>();
        query.eq("location_type", LogisticsConstant.LocationType.PAPER);
        query.eq("used", CommonConstant.Y);
        Integer size = locationInfoMapper.selectCount(query);
        return size;
    }

    @Override
    public LocationInfo getCompanyById(Long id) {
        return locationInfoMapper.selectById(id);
    }


    @Override
    public StatisticsLogistics getStatisticsLogistics(Date startTime, Date endTime) {
        logger.info("====统计货运单相关数据 ===START===");
        StatisticsLogistics statisticsLogistics = new StatisticsLogistics(startTime);
        // 获取指定时间段指定状态的货运单集合
        List<StatisticsOrderInfoVo> statisticsOrderInfoVoList = logisticsOrderInfoMapper.findStatistics(LogisticsConstant.OrderStatus.ALREADY_GATHERING, startTime, endTime, null, null);
        if (CollectionUtils.isEmpty(statisticsOrderInfoVoList)) {
            logger.info("====统计货运单相关数据【{}条】 ===END===", statisticsOrderInfoVoList.size());
            return statisticsLogistics;
        }
        BigDecimal transportTotal = new BigDecimal(0);
        // 总费用
        BigDecimal actualAmount = new BigDecimal(0);
        // 已结算费用
        BigDecimal settlementMoney = new BigDecimal(0);
        for (StatisticsOrderInfoVo item : statisticsOrderInfoVoList) {
            transportTotal = transportTotal.add(item.getTransportTotal());
            actualAmount = actualAmount.add(item.getActualAmount());
            if (item.getStatus() == LogisticsConstant.OrderStatus.ALREADY_COMPLETE) {
                settlementMoney = settlementMoney.add(item.getActualAmount());
            }
        }
        statisticsLogistics.setLogisticsNumber(statisticsOrderInfoVoList.size());
        statisticsLogistics.setLogisticsTotalWeight(transportTotal);
        statisticsLogistics.setLogisticsMoney(actualAmount);
        statisticsLogistics.setLogisticsSettlementMoney(settlementMoney);
        statisticsLogistics.setLogisticsNotSettlementMoney(actualAmount.subtract(settlementMoney));
        logger.info("====统计货运单相关数据【{}条】 ===END===", statisticsOrderInfoVoList.size());

        logger.info("====统计货运支出单相关数据 ===START===");
        List<StatisticsExpensesInfoVo> statisticsExpensesInfoVoList = expensesInfoMapper.findStatistics(LogisticsConstant.ExpensesStatus.WAIT_REFUND, startTime, endTime, null, null);
        if (!CollectionUtils.isEmpty(statisticsExpensesInfoVoList)) {
            int allMileage = 0;
            // 总退费用
            BigDecimal refundableFee = new BigDecimal(0);
            // 已退费用
            BigDecimal alreadyRefundableFee = new BigDecimal(0);
            for (StatisticsExpensesInfoVo item : statisticsExpensesInfoVoList) {
                allMileage += item.getNowMileage() - item.getPreMileage();
                refundableFee = refundableFee.add(item.getRefundableFee());
                if (item.getStatus() == LogisticsConstant.ExpensesStatus.ALREADY_COMPLETE) {
                    alreadyRefundableFee = alreadyRefundableFee.add(item.getRefundableFee());
                }
            }
            statisticsLogistics.setLogisticsMileage(allMileage);
            statisticsLogistics.setExpensesMoney(refundableFee);
            statisticsLogistics.setExpensesSettlementMoney(alreadyRefundableFee);
            statisticsLogistics.setExpensesNotSettlementMoney(refundableFee.subtract(alreadyRefundableFee));
        }
        logger.info("====统计货运支出单相关数据【{}条】 ===END===", statisticsExpensesInfoVoList.size());
        return statisticsLogistics;
    }

    @Override
    public List<StatisticsDriver> getStatisticsDriver(Date startTime, Date endTime) {
        // 获取指定时间段指定状态的货运单集合
        logger.info("====根据驾驶员统计货运单相关数据 ===START===");
        List<StatisticsDriver> statisticsDriverList = new ArrayList<>();

        List<Long> driverIdList = driverInfoMapper.findAllEmpId();
        if (CollectionUtils.isEmpty(driverIdList)) {
            logger.info("====根据驾驶员统计货运单相关数据 ===END===");
            return null;
        }
        // 根据驾驶员id分组
        driverIdList.forEach(driverId -> {
            logger.info("====统计驾驶员id为【{}】的货运单相关数据 ===START===", driverId);
            List<StatisticsOrderInfoVo> driverList = logisticsOrderInfoMapper.findStatistics(LogisticsConstant.OrderStatus.ALREADY_GATHERING, startTime, endTime, driverId, null);
            BigDecimal transportTotal = new BigDecimal(0);
            // 总费用
            BigDecimal actualAmount = new BigDecimal(0);
            // 已结算费用
            BigDecimal settlementMoney = new BigDecimal(0);
            for (StatisticsOrderInfoVo item : driverList) {
                transportTotal = transportTotal.add(item.getTransportTotal());
                actualAmount = actualAmount.add(item.getActualAmount());
                if (item.getStatus() == LogisticsConstant.OrderStatus.ALREADY_COMPLETE) {
                    settlementMoney = settlementMoney.add(item.getActualAmount());
                }
            }
            StatisticsDriver driver = new StatisticsDriver(startTime);
            driver.setDriverId(driverId);
            driver.setLogisticsNumber(driverList.size());
            driver.setLogisticsTotalWeight(transportTotal);
            driver.setLogisticsMoney(actualAmount);
            driver.setLogisticsSettlementMoney(settlementMoney);
            driver.setLogisticsNotSettlementMoney(actualAmount.subtract(settlementMoney));
            logger.info("====统计驾驶员id为【{}】的货运单相关数据【{}条】 ===END===", driverId, driverList.size());

            logger.info("====统计驾驶员id为【{}】的货运支出单相关数据 ===START===", driverId);
            List<StatisticsExpensesInfoVo> statisticsExpensesInfoVoList = expensesInfoMapper.findStatistics(LogisticsConstant.ExpensesStatus.WAIT_REFUND, startTime, endTime, driverId, null);
            if (!CollectionUtils.isEmpty(statisticsExpensesInfoVoList)) {
                int allMileage = 0;
                // 总退费用
                BigDecimal refundableFee = new BigDecimal(0);
                // 已退费用
                BigDecimal alreadyRefundableFee = new BigDecimal(0);
                for (StatisticsExpensesInfoVo item : statisticsExpensesInfoVoList) {
                    allMileage += item.getNowMileage() - item.getPreMileage();
                    refundableFee = refundableFee.add(item.getRefundableFee());
                    if (item.getStatus() == LogisticsConstant.ExpensesStatus.ALREADY_COMPLETE) {
                        alreadyRefundableFee = alreadyRefundableFee.add(item.getRefundableFee());
                    }
                }
                driver.setLogisticsMileage(allMileage);
                driver.setExpensesMoney(refundableFee);
                driver.setExpensesSettlementMoney(alreadyRefundableFee);
                driver.setExpensesNotSettlementMoney(refundableFee.subtract(alreadyRefundableFee));
            }
            statisticsDriverList.add(driver);
            logger.info("====统计驾驶员id为【{}】的货运支出单相关数据【{}条】 ===END===", driverId, statisticsExpensesInfoVoList.size());
        });

        logger.info("====根据驾驶员统计货运单相关数据 ===END===");
        return statisticsDriverList;
    }

    @Override
    public List<StatisticsCar> getStatisticsCar(Date startTime, Date endTime) {
        // 获取指定时间段指定状态的货运单集合
        logger.info("====根据车辆统计货运单相关数据 ===START===");
        List<StatisticsCar> statisticsCarList = new ArrayList<>();
        List<Long> carIdList = carInfoMapper.findAllId();
        if (CollectionUtils.isEmpty(carIdList)) {
            logger.info("====根据车辆统计货运单相关数据 ===END===");
            return null;
        }
        carIdList.forEach(carId -> {
            logger.info("====统计车辆id为【{}】的货运单相关数据 ===START===", carId);
            List<StatisticsOrderInfoVo> carList = logisticsOrderInfoMapper.findStatistics(LogisticsConstant.OrderStatus.ALREADY_GATHERING, startTime, endTime, null, carId);
            StatisticsCar car = new StatisticsCar(startTime);
            BigDecimal transportTotal = new BigDecimal(0);
            // 总费用
            BigDecimal actualAmount = new BigDecimal(0);
            // 已结算费用
            BigDecimal settlementMoney = new BigDecimal(0);
            for (StatisticsOrderInfoVo item : carList) {
                transportTotal = transportTotal.add(item.getTransportTotal());
                actualAmount = actualAmount.add(item.getActualAmount());
                if (item.getStatus() == LogisticsConstant.OrderStatus.ALREADY_COMPLETE) {
                    settlementMoney = settlementMoney.add(item.getActualAmount());
                }
            }
            car.setCarId(carId);
            car.setLogisticsNumber(carList.size());
            car.setLogisticsTotalWeight(transportTotal);
            car.setLogisticsMoney(actualAmount);
            car.setLogisticsSettlementMoney(settlementMoney);
            car.setLogisticsNotSettlementMoney(actualAmount.subtract(settlementMoney));
            logger.info("====统计车辆id为【{}】的货运单相关数据【{}条】 ===END===", carId, carList.size());

            logger.info("====统计车辆id为【{}】的货运支出单相关数据 ===START===", carId);
            List<StatisticsExpensesInfoVo> statisticsExpensesInfoVoList = expensesInfoMapper.findStatistics(LogisticsConstant.ExpensesStatus.WAIT_REFUND, startTime, endTime, null, carId);
            if (!CollectionUtils.isEmpty(statisticsExpensesInfoVoList)) {
                int allMileage = 0;
                // 总退费用
                BigDecimal refundableFee = new BigDecimal(0);
                // 已退费用
                BigDecimal alreadyRefundableFee = new BigDecimal(0);
                for (StatisticsExpensesInfoVo item : statisticsExpensesInfoVoList) {
                    allMileage += item.getNowMileage() - item.getPreMileage();
                    refundableFee = refundableFee.add(item.getRefundableFee());
                    if (item.getStatus() == LogisticsConstant.ExpensesStatus.ALREADY_COMPLETE) {
                        alreadyRefundableFee = alreadyRefundableFee.add(item.getRefundableFee());
                    }
                }
                car.setLogisticsMileage(allMileage);
                car.setExpensesMoney(refundableFee);
                car.setExpensesSettlementMoney(alreadyRefundableFee);
                car.setExpensesNotSettlementMoney(refundableFee.subtract(alreadyRefundableFee));
            }
            statisticsCarList.add(car);
            logger.info("====统计车辆id为【{}】的货运支出单相关数据【{}条】 ===END===", carId, statisticsExpensesInfoVoList.size());
        });
        logger.info("====根据车辆统计货运单相关数据 ===END===");
        return statisticsCarList;
    }

    @Override
    public BigDecimal getLogisticsTotalWeight(String startTime, String endTime, long productId) {
        logger.info("====统计货品id为【{}】的货运总重 ===START===", productId);
        List<BigDecimal> bigDecimalList = logisticsOrderInfoMapper
                .findTransportTotal(LogisticsConstant.OrderStatus.ALREADY_RECEIVING, startTime, endTime, productId);
        BigDecimal totalWeightAll = BigDecimal.ZERO;
        if (!CollectionUtils.isEmpty(bigDecimalList)) {
            for (BigDecimal totalWeight : bigDecimalList) {
                totalWeightAll = totalWeightAll.add(totalWeight);
            }
        }
        logger.info("====统计货品id为【{}】的货运总重【{}】 ===END===", productId, totalWeightAll);
        return totalWeightAll;
    }

    @Override
    public List<Long> getIdsByLeaderId(Long leaderId) {
        return locationInfoMapper.getIdsByLeaderId(leaderId);
    }

    @Override
    public List<Long> getIdsByPurchaseId(Long purchaseId) {
        return locationInfoMapper.getIdsByPurchaseId(purchaseId);
    }

    @Override
    public List<Long> getIdsByCashier(Long cashierId) {
        return locationInfoMapper.getIdsByCashierId(cashierId);
    }
}
